package myJs

import java.util.Base64

import myJs.Utils.{g, _}
import myJs.implicits.Implicits._
import myJs.myPkg.Implicits._
import myJs.myPkg.bootstrap.Bootstrap.default._
import myJs.myPkg.jquery._
import myJs.myPkg._
import org.scalajs.dom.ext.Ajax
import org.scalajs.dom.raw.{Blob, BlobPropertyBag}
import org.scalajs.dom.{Element, Event, document, window}

import scala.collection.immutable.SeqMap
import scala.concurrent.ExecutionContext.Implicits.global
import scala.scalajs.js
import scala.scalajs.js.JSConverters._
import scala.scalajs.js.JSON
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import scalatags.Text.all._

import scala.concurrent.Future
import scala.scalajs.js.typedarray.Uint8Array

/**
 * Created by yz on 11/5/2020
 */
@JSExportTopLevel("SearchResult")
object SearchResult {

  val lsDivId = "linear"
  val bsDivId = "back"
  val fsDivId = "fusionContent"
  val imageTypes = List("Linear & Back", "Fusion")


  @JSExport("init")
  def init = {

    registerEvent

    Tool.useLoadingF() { () =>
      refreshGeneSymbols
      initTable
      bootStrapValidator
      selectGeneSymbol(getGeneSymbols.head, false)
    }
  }

  def registerEvent = {
    $(document.body).on("change", s".myMethod", "", (y: Element) => {
      methodChange(y)
    })
  }

  def methodChange(y: Element) = {
    val myValue = $(y).find(">option:selected").`val`().toString
    Tool.useLoadingF() { () =>
      refreshGenePatternImage
    }

  }

  def refreshTable(geneSymbol: String) = {
    refreshLsTable(geneSymbol)
    refreshBsTable(geneSymbol)
    refreshFsTable(geneSymbol)

  }

  def refreshLsTable(geneSymbol: String) = {
    val url = g.jsRoutes.controllers.SearchController.getAllLsJunctionByGeneSymbol().url.toString
    Ajax.get(url = s"${url}?geneSymbol=${geneSymbol}").map { xhr =>
      val data = xhr.responseText.toJArJDS
      $(s"#${lsDivId} #table").bootstrapTable("load", data)
    }
  }

  def refreshBsTable(geneSymbol: String) = {
    val url = g.jsRoutes.controllers.SearchController.getAllBsJunctionByGeneSymbol().url.toString
    Ajax.get(url = s"${url}?geneSymbol=${geneSymbol}").map { xhr =>
      val data = xhr.responseText.toJArJDS
      $(s"#${bsDivId} #table").bootstrapTable("load", data)
    }
  }

  def refreshFsTable(geneSymbol: String) = {
    val url = g.jsRoutes.controllers.SearchController.getAllFsJunctionByGeneSymbol().url.toString
    Ajax.get(url = s"${url}?geneSymbol=${geneSymbol}").map { xhr =>
      val data = xhr.responseText.toJArJDS
      $(s"#${fsDivId} #table").bootstrapTable("load", data)
    }
  }

  def getGeneSymbols = {
    (g.geneSymbols.toString).split(",")
  }

  def refreshGeneFusionImage = {
    $("#lbMethod").hide()
    val geneSymbol = $(".myBtn.mySelected").attr("id").toString
    val url = g.jsRoutes.controllers.SearchController.generateGeneFusionImage().url.toString
    Ajax.get(url = s"${url}?geneSymbol=${geneSymbol}").map { xhr =>
      val rs = xhr.responseText.toJDJAn
      val valid = rs("valid").toB
      if (valid) {
        val base64 = rs("base64")
        val pdfBase64 = rs("pdfBase64")
        $("#genePatternImage").attr("src", s"data:image/png;base64,${base64}")
        $("#genePatternImage").attr(Tool.dataBasicType, s"pdf")
        Tool.getInputByName("pdfBase64").`val`(pdfBase64.toString)
      } else {
        Swal.swal(SwalOptions.title("Error").text(rs("message")).`type`("error"))
      }
    }
  }

  def refreshGenePatternImage = {
    $("#lbMethod").show()
    val geneSymbol = $(".myBtn.mySelected").attr("id").toString
    val url = g.jsRoutes.controllers.SearchController.generateGenePatternImage().url.toString
    val dict = js.Dictionary(
      "geneSymbol" -> geneSymbol,
      "method" -> Tool.getInputByName("method").myVal
    )
    val data = JSON.stringify(dict)
    Ajax.post(url = s"${url}", data = data, headers = Map("Content-Type" -> "application/json")).map { xhr =>
      val rs = xhr.responseText.toJDJAn
      val valid = rs("valid").toB
      val imageUrl = g.jsRoutes.controllers.SearchController.getGenePatternImage().url.toString
      val dir = "gene_pattern"
      if (valid) {
        val base64 = rs("base64")
        $("#genePatternImage").attr("src", s"data:image/png;base64,${base64}")
        $("#genePatternImage").attr(Tool.dataBasicType, s"png")
      } else {
        $("#genePatternImage").attr("src", s"${imageUrl}?geneSymbol=${geneSymbol}&dir=${dir}")
        Swal.swal(SwalOptions.title("Error").text(rs("message")).`type`("error"))
      }
    }
  }

  def refreshGeneSymbols = {
    val html = getGeneSymbols.map { geneSymbol =>
      a(`class` := "myBtn gene_tag btn btn-default btn-xs", cursor := "pointer", id := s"${geneSymbol}",
        marginBottom := 5,
        onclick := s"SearchResult.selectGeneSymbol('${geneSymbol}')", geneSymbol)
    }.mkString("&nbsp;")
    $("#geneSymbols").html(html)
  }

  def refreshImageType(imageTypes: List[String], curImageType: String = "") = {
    val html = imageTypes.map { kind =>
      a(`class` := "imageType gene_tag btn btn-default btn-xs", cursor := "pointer", id := s"${kind}",
        onclick := s"SearchResult.selectImageType('${kind}')", kind)
    }.mkString("&nbsp;")
    $("#imageType").html(html)
    if (curImageType.isEmpty) {
      $(".imageType:first").addClass("mySelected")
    } else {
      $(s".imageType[id='${curImageType}']").addClass("mySelected")
    }
  }

  @JSExport("selectImageType")
  def selectImageType(kind: String) = {
    Tool.useLoadingF() { () =>
      val colorClass = "mySelected"
      $(".imageType").removeClass(colorClass)
      $(s"a[id='${kind}']").addClass(colorClass)
      if (kind == "Linear & Back") {
        refreshGenePatternImage
      } else {
        refreshGeneFusionImage
      }
    }
  }

  def useLoading(showLoading: Boolean = true)(f: () => Unit) = {
    val index = if (showLoading) {
      layer.alert(Tool.loadingElement, Tool.layerOptions)
    } else 0
    f()
    if (showLoading) {
      layer.close(index)
    }
  }

  def checkInModalSymbols(geneSymbol: String) = {
    val url = g.jsRoutes.controllers.SearchController.checkInModalSymbols().url.toString
    Ajax.get(url = s"${url}?geneSymbol=${geneSymbol}").map { xhr =>
      xhr.responseText.toB
    }
  }

  def checkInFusionSymbols(geneSymbol: String) = {
    val url = g.jsRoutes.controllers.SearchController.checkInFusionSymbols().url.toString
    Ajax.get(url = s"${url}?geneSymbol=${geneSymbol}").map { xhr =>
      xhr.responseText.toB
    }
  }

  @JSExport("myRun")
  def myRun = {
    val bv = jQuery(s"#form").data("bootstrapValidator")
    bv.validate()
    val valid = bv.isValid().toB
    if (valid) {
      val geneSymbol = $(".myBtn.mySelected").attr("id").toString
      selectGeneSymbol(geneSymbol, true, isReset = false)
    }

  }

  @JSExport("selectGeneSymbol")
  def selectGeneSymbol(geneSymbol: String, showLoading: Boolean = true, isReset: Boolean = true) = {
    if (isReset) g.myReset()
    Tool.useLoadingF(showLoading) { () =>
      val colorClass = "mySelected"
      $(".myBtn").removeClass(colorClass)
      $(s"a[id='${geneSymbol}']").addClass(colorClass)
      checkInFusionSymbols(geneSymbol).zip(checkInModalSymbols(geneSymbol)).map { case (b, modalB) =>
        val curImageType = getImageType
        if (modalB && !b) {
          refreshImageType(List(imageTypes.head))
        } else if (!modalB && b) {
          refreshImageType(imageTypes.tail)
        } else if (!modalB && !b) {
          refreshImageType(List())
          $("#imageResult").hide()
        } else {
          refreshImageType(imageTypes, curImageType)
        }
        if (modalB || b) {
          $("#imageResult").show()
        }
      }.flatMap { x =>
        refreshImage.zip(refreshTable(geneSymbol))
      }
    }
  }

  def getImageType = {
    $(".imageType.mySelected").attr("id").getOrElse("")
  }

  def refreshImage = {
    val imageType = getImageType
    imageType match {
      case x if x == imageTypes.head => refreshGenePatternImage
      case x if x == imageTypes.last => refreshGeneFusionImage
      case _ => Future {}
    }
  }

  def tbFmt(columnName: String, kind: String): js.Function = (v: js.Any, row: js.Dictionary[js.Any]) => columnName match {
    case "junctionId" =>
      val url = g.jsRoutes.controllers.SearchController.detailInfoBefore().url.toString
      a(title := "detail", href := s"${url}?junctionId=${v}&kind=${kind}", cursor.pointer, target := "_blank",
        v.toString
      )
    case _ => if (v.toString.isDouble) {
      v.toString.toDouble.toFixed(Tool.decDigits)
    } else v
  }

  def initTable = {
    initLsTable
    initBsTable
    initFsTable
  }

  def initLsTable = {
    val divId = "linear"
    val tableId = s"#${divId} #table"
    val tableJq = $(tableId)
    val checkboxJq = $(s"#${divId} #checkbox")
    val map = SeqMap("junctionId" -> "JunctionID", "junctionLocation" -> "Junction location",
      "geneSymbol" -> "Gene symbol", "geneType" -> "Gene type",
      "transcriptId" -> "Transcript ID", "tumorMedian" -> "Tumor median", "ntMedian" -> "NT median",
      "normalMedian" -> "Normal median", "tumorFreq" -> "Tumor frequency(sample number)",
      "ntFreq" -> "NT frequency(sample number)", "normalFreq" -> "Normal frequency(sample number)",
      "tumorSpecificTypes" -> "Tumor specific types",
      "alternativeSplicingTypes" -> "Alternative splicing types", "annotation" -> "Annotation",
      "tumorAssociatedGene" -> "Tumor associated gene"
    )
    val columnNames = map.keyList
    val columns = columnNames.map { columnName =>
      val title = map.getOrElse(columnName, columnName)
      val fmt = tbFmt(columnName, "ls")
      val basicOptions = ColumnOptions.field(columnName).title(title).formatter(fmt).sortable(true)
      columnName match {
        case _ => basicOptions
      }
    }
    val exportOptions = ExportOptions.fileName("linear_splice_junction.csv").exportHiddenColumns(true)
    val options = TableOptions.columns(columns.toJSArray).search(true).exportOptions(exportOptions).showExport(true).
      exportDataType("all").exportTypes(js.Array("csv"))
    tableJq.bootstrapTable(options)
    Tool.refreshCheckboxView(map.tail, checkboxJq, s"#${divId}")
    val hideColumns = map.keyList.filterNot { x =>
      List("junctionId", "junctionLocation", "geneSymbol", "geneType", "tumorMedian", "tumorFreq",
        "tumorSpecificTypes", "annotation").contains(x)
    }
    hideColumns.foreach { x =>
      tableJq.bootstrapTable("hideColumn", x)
      $(s"#${divId} input:checkbox[value='${x}']").attr("checked", false)
    }
    bindEvt
  }

  def initBsTable = {
    val divId = "back"
    val tableId = s"#${divId} #table"
    val tableJq = $(tableId)
    val checkboxJq = $(s"#${divId} #checkbox")
    val map = SeqMap("junctionId" -> "JunctionID", "junctionLocation" -> "Junction location",
      "geneSymbol" -> "Gene symbol", "geneType" -> "Gene type",
      "transcriptId" -> "Transcript ID", "tumorMedian" -> "Tumor median", "tumorFreq" -> "Tumor frequency(sample number)",
      "tumorAssociatedGene" -> "Tumor associated gene"
    )
    val columnNames = map.keyList
    val columns = columnNames.map { columnName =>
      val title = map.getOrElse(columnName, columnName)
      val fmt = tbFmt(columnName, "bs")
      val basicOptions = ColumnOptions.field(columnName).title(title).formatter(fmt).sortable(true)
      columnName match {
        case _ => basicOptions
      }
    }
    val exportOptions = ExportOptions.fileName("back_splice_junction.csv").exportHiddenColumns(true)
    val options = TableOptions.columns(columns.toJSArray).search(true).exportOptions(exportOptions).showExport(true).
      exportDataType("all").exportTypes(js.Array("csv"))
    tableJq.bootstrapTable(options)
    Tool.refreshCheckboxView(map.tail, checkboxJq, s"#${divId}")
    val hideColumns = map.keyList.filterNot { x =>
      map.keyList.take(6).contains(x)
    }
    hideColumns.foreach { x =>
      tableJq.bootstrapTable("hideColumn", x)
      $(s"#${divId} input:checkbox[value='${x}']").attr("checked", false)
    }
    bindEvt
  }

  def initFsTable = {
    val divId = fsDivId
    val tableId = s"#${divId} #table"
    val tableJq = $(tableId)
    val checkboxJq = $(s"#${divId} #checkbox")
    val map = SeqMap("junctionId" -> "JunctionID", "junctionLocation" -> "Junction location",
      "geneSymbol1" -> "Gene symbol 1", "geneSymbol2" -> "Gene symbol 2", "geneType1" -> "Gene type 1",
      "geneType2" -> "Gene type 2",
      "tumorMedian" -> "Tumor median", "tumorFreq" -> "Tumor frequency(sample number)",
      "tumorAssociatedGene1" -> "Tumor associated gene 1", "tumorAssociatedGene2" -> "Tumor associated gene 2"
    )
    val columnNames = map.keyList
    val columns = columnNames.map { columnName =>
      val title = map.getOrElse(columnName, columnName)
      val fmt = tbFmt(columnName, "fs")
      val basicOptions = ColumnOptions.field(columnName).title(title).formatter(fmt).sortable(true)
      columnName match {
        case _ => basicOptions
      }
    }
    val exportOptions = ExportOptions.fileName("fusion_splice_junction.csv").exportHiddenColumns(true)
    val options = TableOptions.columns(columns.toJSArray).search(true).exportOptions(exportOptions).showExport(true).
      exportDataType("all").exportTypes(js.Array("csv"))
    tableJq.bootstrapTable(options)
    Tool.refreshCheckboxView(map.tail, checkboxJq, s"#${divId}")
    val hideColumns = map.keyList.filterNot { x =>
      map.keyList.take(6).contains(x)
    }
    hideColumns.foreach { x =>
      tableJq.bootstrapTable("hideColumn", x)
      $(s"#${divId} input:checkbox[value='${x}']").attr("checked", false)
    }
    bindEvt
  }


  def bindEvt = {

  }

  def bootStrapValidator = {
    val dict = js.Dictionary(
      "feedbackIcons" -> js.Dictionary(
        "valid" -> "glyphicon glyphicon-ok",
        "invalid" -> "glyphicon glyphicon-remove",
        "validating" -> "glyphicon glyphicon-refresh",
      ),
      "fields" -> js.Dictionary(
        "color" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "color is required！"
            ),
          )
        ),
      )
    )
    g.$("#form").bootstrapValidator(dict)
  }


}
